Overall Objective

Load Libraries

library(tidyverse)
library(cowplot)
library(broom)
library(plotly)

Import data

Convert data from ‘wide’ to ‘long’ format

# data
data1 <- data %>%
  gather(Sample,Count,2:145)
# Separate samples by identifiers 
data2 <- data1 %>% 
  separate(Sample, into=c("Sample_ID","Dilution_factor",
                          "Injection","Tech_rep", sep = "_")) %>% 
  select(-`_`)
# Standards
standards1 <- standards %>% 
  gather(Sample,Count,2:49)
standards2 <- standards1 %>% 
  separate(Sample, into=c("Sample_ID","When","Dilution_factor",
                          "Nano_day","Injection","Tech_Rep", sep = "_")) %>% 
  select(-`_`)

Factor the data into categorical variables

# Refactoring Columns for samples
data2$Sample_ID <- as.factor(data2$Sample_ID)
data2$Dilution_factor <- as.numeric(data2$Dilution_factor)
data2$Injection<- as.factor(data2$Injection)
data2$Tech_rep <- as.numeric(data2$Tech_rep)
# Refactoring COlumns for key
key$Sample_ID <- as.factor(key$Sample_ID)
key$Time <- as.factor(key$Time)
key$Treatment <- as.factor(key$Treatment)
key$Volume <- as.numeric(key$Volume)
key$Patient_ID <- as.factor(key$Patient_ID)
key$Treatment <- factor(key$Treatment,levels = c('DMSO','EGF','BPS','BPS_EGF'))
key$Patient_ID <- factor(key$Patient_ID,levels = c('1','5','7'))
# Refactoring columns for standards
standards2$Sample_ID <- as.factor(standards2$Sample_ID)
standards2$When <- as.factor(standards2$When)
standards2$Dilution_factor <- as.numeric(standards2$Dilution_factor)
standards2$Injection <- as.factor(standards2$Injection)
standards2$Nano_day <- as.numeric(standards2$Nano_day)

Back calculate standards

standards2 <- standards2 %>% 
  mutate(True_Count=Dilution_factor*Count)
# Set the correct order of 'categorical factors'
standards2$Nano_day <-  factor(standards2$Nano_day, levels=c('1','2','3','4'))
standards2$When <- factor(standards2$When, levels=c('before','after'))

Summarize three technical standard replicates

standards3 <- standards2 %>% 
  group_by(particle_size,Sample_ID,When,Dilution_factor,Nano_day,Injection) %>% 
  summarise( tech_N = length(True_Count),
             tech_mean = mean(True_Count),
             tech_sd = sd(True_Count),
             tech_se = tech_sd/sqrt(tech_N))
standards3

Summarize standards by injection

standards4 <- standards3 %>% 
  group_by(Nano_day,When,particle_size) %>% 
  summarise( inj_N = length(tech_mean),
             inj_mean = mean(tech_mean),
             inj_sd = sd(tech_mean),
             inj_se = inj_sd/sqrt(inj_N))
standards4

Plot before and after plots, facet by experimental day

std_plot <- standards4 %>% 
  ggplot(aes(x = particle_size, y = inj_mean, color=When))+
  geom_line(size=2) + xlim(0,300)+ #line size, x-axis scale
  geom_ribbon(aes(ymin=inj_mean-inj_se, ymax=inj_mean+inj_se),
              alpha=0.4,fill = alpha('grey12', 0.2)) + #error bars
  scale_y_continuous(expand=c(0,0))+ #set bottom of graph
  xlab("Particle Size") + # X axis label
  ylab("\nMean Particle Concentration/ml\n") + # Y axis label
  ggtitle("Nanosight Histogram of\n100nm Standards")+ #title
  labs(color="Condition")+ #Label table title
  facet_wrap(~ Nano_day)
std_plot
ggsave("Standards_histogram_plot.png",
       height = 5, width = 7, dpi = 300, units= "in")

Standards particle concentrations from each experimental day

standards_df <- standards4 %>% 
  group_by(Nano_day,When) %>% 
  summarise(total=sum(inj_mean))
standards_df

Bar graph of standards particle concentrations

standards_bar <- standards_df %>% 
  ggplot(aes(x=Nano_day,y=total,fill=When))+
  geom_col(position="dodge")+
  scale_y_continuous(expand=c(0,0))+ #set bottom of graph
  xlab("Experimental Day") + # X axis label
  ylab("\nMean Particle Concentration/ml\n") + # Y axis label
  ggtitle("Nanosight Histogram of\n100nm Standards")+ #title
  labs(color="When") #Label table title
standards_bar
ggsave("Standards_bar_plot.png",
       height = 5, width = 7, dpi = 300, units= "in")

Intraassay variability

Intra.assay_cv <- standards_df %>% 
  group_by(Nano_day) %>% 
  summarise(Intra_Day_N = length(total),
            Intra_Day_mean = mean(total),
            Intra_Day_sd = sd(total),
            Intra_Day_se = Intra_Day_sd/sqrt(Intra_Day_N),
            Intra_Day_cv = Intra_Day_sd/Intra_Day_mean )
Intra.assay_cv
# # Save as .csv
# write_csv(Intra.assay_cv,"Intra.assay_cv.csv")

Interassay variability

Inter.assay_cv <- Intra.assay_cv %>% 
  summarise(Inter_Day_N = length(Intra_Day_mean),
            Inter_Day_mean = mean(Intra_Day_mean),
            Inter_Day_sd = sd(Intra_Day_mean),
            Inter_Day_se = Inter_Day_sd/sqrt(Inter_Day_N),
            Inter_Day_cv = Inter_Day_sd/Inter_Day_mean )
Inter.assay_cv
# # Save as .csv
# write_csv(Inter.assay_cv,"Inter.assay_cv.csv")

Sample analysis

Back calculate the original concentration of the sample

rr # # Save as .csv # write_csv(Inter.assay_cv,.assay_cv.csv)

Average three technical readings

data3 <- data2 %>% 
  group_by(particle_size,Sample_ID,Dilution_factor,Injection) %>% 
  summarise( tech_N = length(True_Count),
             tech_mean = mean(True_Count),
             tech_sd = sd(True_Count),
             tech_se = tech_sd/sqrt(tech_N))
data3

Summarize samples by injection (average both injections)

data4 <- data3 %>% 
  group_by(particle_size,Sample_ID,Dilution_factor) %>% 
  summarise( inj_N = length(tech_mean),
             inj_mean = mean(tech_mean),
             inj_sd = sd(tech_mean),
             inj_se = inj_sd/sqrt(inj_N))
data4
# Average technical replicates and merge with key
merge <- left_join(key,data3, by= "Sample_ID")
merge
# Save as .csv
# write_csv(merge,"Technical_replicate_average.csv")
 
# Average injection replicates and merge with key
merge1 <- left_join(key,data4, by= "Sample_ID")
merge1
# #Save as .csv
# write_csv(merge1,"Injection_replicate_average.csv")

Quick visualizations

Graphing all samples

sample_plot <- merge %>%
  ggplot(aes(x=particle_size, y=tech_mean,color=Injection ))+ #plot
  geom_ribbon(aes(ymin=tech_mean-tech_se,
                  ymax=tech_mean+tech_se),
                  alpha=0.2,fill = alpha('grey12', 0.2)) + #error bars
  geom_line(size=2.0, alpha = 0.8) + xlim(0,500)+ #line size, x-axis scale
  scale_y_continuous(expand=c(0,0))+ #set bottom of graph
  xlab("Particle Size") + # X axis label
  ylab("\nMean Particle Concentration/ml\n") + # Y axis label
  ggtitle("Nanosight Histogram of\nhCTBS treated with BPS")+ #title
  labs(color="Injection")+ #Label table title
  facet_grid(Time ~ Treatment)
  # geom_vline(xintercept = 200)+
  # annotate("text", x= 350, y = 1E8, label= "200nm")
sample_plot

# ggsave("Nanosight_Sample_Histogram.png", plot = sample_plot,
#        height = 10, width = 14, dpi = 200, units= "in")

Interactive Plot

ggplotly(sample_plot)

Particle concentration values for each of the samples

merge2 <- merge1 %>% 
  group_by(Time, Treatment, Volume,Patient_ID) %>% 
  summarise(particle_conc=sum(inj_mean))
merge2

Correct for resuspension volume

merge3 <- merge2 %>% 
  mutate(particle_count = (Volume/1000)*particle_conc, # Create new column with number of particles
         corrected_particle_conc = (particle_conc/1E9)) # Create new column with correct particle concentration
merge3
# Save as .csv
# write_csv(merge3,"Adjusted_particle_concentration.csv")

Barplot

merge3$Patient_ID <- factor(merge3$Patient_ID,levels = c('1','5','7'))
plot1 <- merge3 %>%
  ggplot(aes(x = Treatment, y = corrected_particle_conc, fill = Patient_ID)) +
  geom_bar(aes(text = paste("Particle Concentration:",
                            corrected_particle_conc)),
           stat="identity", position = "dodge")+
  xlab("\nTreatment\n") + # X axis label
  ylab("\nMean Vessicle Concentration\n(10^9 particles/ ml)\n") + # Y axis label
  ggtitle("Effect of BPS on Extracellular Vessicle\nRelease of hCTBs\n")+
  scale_y_continuous(breaks = seq(0,14,2),
                     limits = c(0,14),
                     expand = c(0,0))+ # set bottom of graph
  labs(color="Condition")+ # Label table title
  facet_wrap(~Time)
Ignoring unknown aesthetics: text
  
plot1
ggsave("BPS_treated_hCTBs_48_96_facet_plot.png",
      height = 8, width = 10, dpi = 300, units= "in")

Interactive Plot

ggplotly(plot1)

Boxplot

plot2 <- merge3 %>%
  group_by(Time, Treatment) %>% 
  ggplot(aes(x = Treatment, y = corrected_particle_conc, color = Patient_ID )) +
  geom_boxplot(color = "black", fill = NA)+
  geom_point(aes(text = paste ("Patient_ID",Patient_ID)),position = 'jitter', size = 5)+
  xlab("\nTreatment\n") + # X axis label
  ylab("\nMean Vessicle Concentration\n(10^9 particles/ ml)\n") + # Y axis label
  ggtitle("Effect of BPS on Extracellular Vessicle\nRelease of hCTBs\n")+
  labs(fill= "Time (hr)")+
  facet_wrap(~Time)
Ignoring unknown aesthetics: text
plot2
 ggsave("BPS_treated_hCTBs_48_96_plot.png",
       height = 5, width = 7, dpi = 500, units= "in")

Interactive Plot

ggplotly(plot2)

Statistics

tidy(shapiro.test(merge3$particle_conc))
fit <- aov(corrected_particle_conc ~ Time * Treatment, data=merge3)
tidy(fit)
tukey_fit <- TukeyHSD(fit)
tukey <- tidy(tukey_fit)
tukey
tukey %>% 
  filter(adj.p.value <0.05) %>% 
  arrange(adj.p.value)
LS0tDQp0aXRsZTogIkh1bWFuIENUQiBCUFMgUHJvamVjdCINCmF1dGhvcjogIlNlYW4gTmd1eWVuIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0aGVtZTogZmxhdGx5DQogIGh0bWxfbm90ZWJvb2s6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQojT3ZlcmFsbCBPYmplY3RpdmUgDQoNCg0KIyNMb2FkIExpYnJhcmllcw0KDQpgYGB7ciwgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGNvd3Bsb3QpDQpsaWJyYXJ5KGJyb29tKQ0KbGlicmFyeShwbG90bHkpDQoNCmBgYA0KDQojI0ltcG9ydCBkYXRhDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCnNldHdkKCJ+L0dpdEh1Yi9FeHBlcmltZW50cy9DVEJfQlBTL2RhdGEvIikNCiMgc2V0d2QoIn4vTGlicmFyeS9Nb2JpbGUgRG9jdW1lbnRzL2NvbX5hcHBsZX5DbG91ZERvY3MvRXhwZXJpbWVudHMvQ1RCX0JQUy9kYXRhLyIpDQoNCg0KcmF3X2RhdGEgPC0gIkNUQl9waWxvdF80OGhyXzk2aHItRXhwZXJpbWVudFN1bW1hcnkuY3N2Ig0Ka2V5X2RhdGEgPC0gIktleV9oQ1RCUGV0cm9mZl9Mb3Blei5jc3YiDQpzdGFuZGFyZF9kYXRhIDwtICJzdGRfQ1RCX3BpbG90XzQ4aHJfOTZoci1FeHBlcmltZW50U3VtbWFyeS5jc3YiDQoNCg0KZGF0YSA8LSByZWFkX2NzdihyYXdfZGF0YSkNCnN0YW5kYXJkcyA8LSByZWFkX2NzdihzdGFuZGFyZF9kYXRhKQ0Ka2V5IDwtIHJlYWRfY3N2KGtleV9kYXRhKQ0KDQpgYGANCg0KIyNDb252ZXJ0IGRhdGEgZnJvbSAnd2lkZScgdG8gJ2xvbmcnIGZvcm1hdA0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIGRhdGENCmRhdGExIDwtIGRhdGEgJT4lDQogIGdhdGhlcihTYW1wbGUsQ291bnQsMjoxNDUpDQoNCiMgU2VwYXJhdGUgc2FtcGxlcyBieSBpZGVudGlmaWVycyANCmRhdGEyIDwtIGRhdGExICU+JSANCiAgc2VwYXJhdGUoU2FtcGxlLCBpbnRvPWMoIlNhbXBsZV9JRCIsIkRpbHV0aW9uX2ZhY3RvciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJJbmplY3Rpb24iLCJUZWNoX3JlcCIsIHNlcCA9ICJfIikpICU+JSANCiAgc2VsZWN0KC1gX2ApDQoNCiMgU3RhbmRhcmRzDQpzdGFuZGFyZHMxIDwtIHN0YW5kYXJkcyAlPiUgDQogIGdhdGhlcihTYW1wbGUsQ291bnQsMjo0OSkNCg0KDQpzdGFuZGFyZHMyIDwtIHN0YW5kYXJkczEgJT4lIA0KICBzZXBhcmF0ZShTYW1wbGUsIGludG89YygiU2FtcGxlX0lEIiwiV2hlbiIsIkRpbHV0aW9uX2ZhY3RvciIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICJOYW5vX2RheSIsIkluamVjdGlvbiIsIlRlY2hfUmVwIiwgc2VwID0gIl8iKSkgJT4lIA0KICBzZWxlY3QoLWBfYCkNCg0KDQpgYGANCg0KDQojI0ZhY3RvciB0aGUgZGF0YSBpbnRvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcw0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojIFJlZmFjdG9yaW5nIENvbHVtbnMgZm9yIHNhbXBsZXMNCmRhdGEyJFNhbXBsZV9JRCA8LSBhcy5mYWN0b3IoZGF0YTIkU2FtcGxlX0lEKQ0KZGF0YTIkRGlsdXRpb25fZmFjdG9yIDwtIGFzLm51bWVyaWMoZGF0YTIkRGlsdXRpb25fZmFjdG9yKQ0KZGF0YTIkSW5qZWN0aW9uPC0gYXMuZmFjdG9yKGRhdGEyJEluamVjdGlvbikNCmRhdGEyJFRlY2hfcmVwIDwtIGFzLm51bWVyaWMoZGF0YTIkVGVjaF9yZXApDQoNCg0KIyBSZWZhY3RvcmluZyBDT2x1bW5zIGZvciBrZXkNCmtleSRTYW1wbGVfSUQgPC0gYXMuZmFjdG9yKGtleSRTYW1wbGVfSUQpDQprZXkkVGltZSA8LSBhcy5mYWN0b3Ioa2V5JFRpbWUpDQprZXkkVHJlYXRtZW50IDwtIGFzLmZhY3RvcihrZXkkVHJlYXRtZW50KQ0Ka2V5JFZvbHVtZSA8LSBhcy5udW1lcmljKGtleSRWb2x1bWUpDQprZXkkUGF0aWVudF9JRCA8LSBhcy5mYWN0b3Ioa2V5JFBhdGllbnRfSUQpDQoNCmtleSRUcmVhdG1lbnQgPC0gZmFjdG9yKGtleSRUcmVhdG1lbnQsbGV2ZWxzID0gYygnRE1TTycsJ0VHRicsJ0JQUycsJ0JQU19FR0YnKSkNCmtleSRQYXRpZW50X0lEIDwtIGZhY3RvcihrZXkkUGF0aWVudF9JRCxsZXZlbHMgPSBjKCcxJywnNScsJzcnKSkNCg0KDQojIFJlZmFjdG9yaW5nIGNvbHVtbnMgZm9yIHN0YW5kYXJkcw0Kc3RhbmRhcmRzMiRTYW1wbGVfSUQgPC0gYXMuZmFjdG9yKHN0YW5kYXJkczIkU2FtcGxlX0lEKQ0Kc3RhbmRhcmRzMiRXaGVuIDwtIGFzLmZhY3RvcihzdGFuZGFyZHMyJFdoZW4pDQpzdGFuZGFyZHMyJERpbHV0aW9uX2ZhY3RvciA8LSBhcy5udW1lcmljKHN0YW5kYXJkczIkRGlsdXRpb25fZmFjdG9yKQ0Kc3RhbmRhcmRzMiRJbmplY3Rpb24gPC0gYXMuZmFjdG9yKHN0YW5kYXJkczIkSW5qZWN0aW9uKQ0Kc3RhbmRhcmRzMiROYW5vX2RheSA8LSBhcy5udW1lcmljKHN0YW5kYXJkczIkTmFub19kYXkpDQoNCmBgYA0KDQoNCg0KIyMjQmFjayBjYWxjdWxhdGUgc3RhbmRhcmRzDQpgYGB7cn0NCnN0YW5kYXJkczIgPC0gc3RhbmRhcmRzMiAlPiUgDQogIG11dGF0ZShUcnVlX0NvdW50PURpbHV0aW9uX2ZhY3RvcipDb3VudCkNCg0KIyBTZXQgdGhlIGNvcnJlY3Qgb3JkZXIgb2YgJ2NhdGVnb3JpY2FsIGZhY3RvcnMnDQpzdGFuZGFyZHMyJE5hbm9fZGF5IDwtICBmYWN0b3Ioc3RhbmRhcmRzMiROYW5vX2RheSwgbGV2ZWxzPWMoJzEnLCcyJywnMycsJzQnKSkNCnN0YW5kYXJkczIkV2hlbiA8LSBmYWN0b3Ioc3RhbmRhcmRzMiRXaGVuLCBsZXZlbHM9YygnYmVmb3JlJywnYWZ0ZXInKSkNCg0KYGBgDQoNCiMjI1N1bW1hcml6ZSB0aHJlZSB0ZWNobmljYWwgc3RhbmRhcmQgcmVwbGljYXRlcw0KYGBge3J9DQpzdGFuZGFyZHMzIDwtIHN0YW5kYXJkczIgJT4lIA0KICBncm91cF9ieShwYXJ0aWNsZV9zaXplLFNhbXBsZV9JRCxXaGVuLERpbHV0aW9uX2ZhY3RvcixOYW5vX2RheSxJbmplY3Rpb24pICU+JSANCiAgc3VtbWFyaXNlKCB0ZWNoX04gPSBsZW5ndGgoVHJ1ZV9Db3VudCksDQogICAgICAgICAgICAgdGVjaF9tZWFuID0gbWVhbihUcnVlX0NvdW50KSwNCiAgICAgICAgICAgICB0ZWNoX3NkID0gc2QoVHJ1ZV9Db3VudCksDQogICAgICAgICAgICAgdGVjaF9zZSA9IHRlY2hfc2Qvc3FydCh0ZWNoX04pKQ0Kc3RhbmRhcmRzMw0KYGBgDQoNCg0KIyMjU3VtbWFyaXplIHN0YW5kYXJkcyBieSBpbmplY3Rpb24NCmBgYHtyfQ0Kc3RhbmRhcmRzNCA8LSBzdGFuZGFyZHMzICU+JSANCiAgZ3JvdXBfYnkoTmFub19kYXksV2hlbixwYXJ0aWNsZV9zaXplKSAlPiUgDQogIHN1bW1hcmlzZSggaW5qX04gPSBsZW5ndGgodGVjaF9tZWFuKSwNCiAgICAgICAgICAgICBpbmpfbWVhbiA9IG1lYW4odGVjaF9tZWFuKSwNCiAgICAgICAgICAgICBpbmpfc2QgPSBzZCh0ZWNoX21lYW4pLA0KICAgICAgICAgICAgIGlual9zZSA9IGlual9zZC9zcXJ0KGlual9OKSkNCnN0YW5kYXJkczQNCg0KYGBgDQoNCiMjI1Bsb3QgYmVmb3JlIGFuZCBhZnRlciBwbG90cywgZmFjZXQgYnkgZXhwZXJpbWVudGFsIGRheQ0KYGBge3J9DQpzdGRfcGxvdCA8LSBzdGFuZGFyZHM0ICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gcGFydGljbGVfc2l6ZSwgeSA9IGlual9tZWFuLCBjb2xvcj1XaGVuKSkrDQogIGdlb21fbGluZShzaXplPTIpICsgeGxpbSgwLDMwMCkrICNsaW5lIHNpemUsIHgtYXhpcyBzY2FsZQ0KICBnZW9tX3JpYmJvbihhZXMoeW1pbj1pbmpfbWVhbi1pbmpfc2UsIHltYXg9aW5qX21lYW4raW5qX3NlKSwNCiAgICAgICAgICAgICAgYWxwaGE9MC40LGZpbGwgPSBhbHBoYSgnZ3JleTEyJywgMC4yKSkgKyAjZXJyb3IgYmFycw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoMCwwKSkrICNzZXQgYm90dG9tIG9mIGdyYXBoDQogIHhsYWIoIlBhcnRpY2xlIFNpemUiKSArICMgWCBheGlzIGxhYmVsDQogIHlsYWIoIlxuTWVhbiBQYXJ0aWNsZSBDb25jZW50cmF0aW9uL21sXG4iKSArICMgWSBheGlzIGxhYmVsDQogIGdndGl0bGUoIk5hbm9zaWdodCBIaXN0b2dyYW0gb2ZcbjEwMG5tIFN0YW5kYXJkcyIpKyAjdGl0bGUNCiAgbGFicyhjb2xvcj0iQ29uZGl0aW9uIikrICNMYWJlbCB0YWJsZSB0aXRsZQ0KICBmYWNldF93cmFwKH4gTmFub19kYXkpDQoNCnN0ZF9wbG90DQoNCg0KIyBnZ3NhdmUoIlN0YW5kYXJkc19oaXN0b2dyYW1fcGxvdC5wbmciLA0KIyAgICAgICAgaGVpZ2h0ID0gNSwgd2lkdGggPSA3LCBkcGkgPSAzMDAsIHVuaXRzPSAiaW4iKQ0KYGBgDQoNCiMjIyBTdGFuZGFyZHMgcGFydGljbGUgY29uY2VudHJhdGlvbnMgZnJvbSBlYWNoIGV4cGVyaW1lbnRhbCBkYXkNCmBgYHtyfQ0Kc3RhbmRhcmRzX2RmIDwtIHN0YW5kYXJkczQgJT4lIA0KICBncm91cF9ieShOYW5vX2RheSxXaGVuKSAlPiUgDQogIHN1bW1hcmlzZSh0b3RhbD1zdW0oaW5qX21lYW4pKQ0KDQpzdGFuZGFyZHNfZGYNCmBgYA0KDQojIyNCYXIgZ3JhcGggb2Ygc3RhbmRhcmRzIHBhcnRpY2xlIGNvbmNlbnRyYXRpb25zDQpgYGB7cn0NCnN0YW5kYXJkc19iYXIgPC0gc3RhbmRhcmRzX2RmICU+JSANCiAgZ2dwbG90KGFlcyh4PU5hbm9fZGF5LHk9dG90YWwsZmlsbD1XaGVuKSkrDQogIGdlb21fY29sKHBvc2l0aW9uPSJkb2RnZSIpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoMCwwKSkrICNzZXQgYm90dG9tIG9mIGdyYXBoDQogIHhsYWIoIkV4cGVyaW1lbnRhbCBEYXkiKSArICMgWCBheGlzIGxhYmVsDQogIHlsYWIoIlxuTWVhbiBQYXJ0aWNsZSBDb25jZW50cmF0aW9uL21sXG4iKSArICMgWSBheGlzIGxhYmVsDQogIGdndGl0bGUoIk5hbm9zaWdodCBIaXN0b2dyYW0gb2ZcbjEwMG5tIFN0YW5kYXJkcyIpKyAjdGl0bGUNCiAgbGFicyhjb2xvcj0iV2hlbiIpICNMYWJlbCB0YWJsZSB0aXRsZQ0KDQpzdGFuZGFyZHNfYmFyDQoNCiMgZ2dzYXZlKCJTdGFuZGFyZHNfYmFyX3Bsb3QucG5nIiwNCiMgICAgICAgIGhlaWdodCA9IDUsIHdpZHRoID0gNywgZHBpID0gMzAwLCB1bml0cz0gImluIikNCmBgYA0KDQojIyNJbnRyYWFzc2F5IHZhcmlhYmlsaXR5DQpgYGB7cn0NCkludHJhLmFzc2F5X2N2IDwtIHN0YW5kYXJkc19kZiAlPiUgDQogIGdyb3VwX2J5KE5hbm9fZGF5KSAlPiUgDQogIHN1bW1hcmlzZShJbnRyYV9EYXlfTiA9IGxlbmd0aCh0b3RhbCksDQogICAgICAgICAgICBJbnRyYV9EYXlfbWVhbiA9IG1lYW4odG90YWwpLA0KICAgICAgICAgICAgSW50cmFfRGF5X3NkID0gc2QodG90YWwpLA0KICAgICAgICAgICAgSW50cmFfRGF5X3NlID0gSW50cmFfRGF5X3NkL3NxcnQoSW50cmFfRGF5X04pLA0KICAgICAgICAgICAgSW50cmFfRGF5X2N2ID0gSW50cmFfRGF5X3NkL0ludHJhX0RheV9tZWFuICkNCkludHJhLmFzc2F5X2N2DQoNCiMgIyBTYXZlIGFzIC5jc3YNCiMgd3JpdGVfY3N2KEludHJhLmFzc2F5X2N2LCJJbnRyYS5hc3NheV9jdi5jc3YiKQ0KYGBgDQoNCiMjI0ludGVyYXNzYXkgdmFyaWFiaWxpdHkNCmBgYHtyfQ0KSW50ZXIuYXNzYXlfY3YgPC0gSW50cmEuYXNzYXlfY3YgJT4lIA0KICBzdW1tYXJpc2UoSW50ZXJfRGF5X04gPSBsZW5ndGgoSW50cmFfRGF5X21lYW4pLA0KICAgICAgICAgICAgSW50ZXJfRGF5X21lYW4gPSBtZWFuKEludHJhX0RheV9tZWFuKSwNCiAgICAgICAgICAgIEludGVyX0RheV9zZCA9IHNkKEludHJhX0RheV9tZWFuKSwNCiAgICAgICAgICAgIEludGVyX0RheV9zZSA9IEludGVyX0RheV9zZC9zcXJ0KEludGVyX0RheV9OKSwNCiAgICAgICAgICAgIEludGVyX0RheV9jdiA9IEludGVyX0RheV9zZC9JbnRlcl9EYXlfbWVhbiApDQpJbnRlci5hc3NheV9jdg0KDQojICMgU2F2ZSBhcyAuY3N2DQojIHdyaXRlX2NzdihJbnRlci5hc3NheV9jdiwiSW50ZXIuYXNzYXlfY3YuY3N2IikNCmBgYA0KDQoNCg0KI1NhbXBsZSBhbmFseXNpcw0KDQojIyNCYWNrIGNhbGN1bGF0ZSB0aGUgb3JpZ2luYWwgY29uY2VudHJhdGlvbiBvZiB0aGUgc2FtcGxlDQpgYGB7cn0NCmRhdGEyIDwtIGRhdGEyICU+JSANCiAgbXV0YXRlKFRydWVfQ291bnQgPSBEaWx1dGlvbl9mYWN0b3IqQ291bnQpDQpkYXRhMg0KYGBgDQoNCg0KIyMjIEF2ZXJhZ2UgdGhyZWUgdGVjaG5pY2FsIHJlYWRpbmdzDQpgYGB7cn0NCmRhdGEzIDwtIGRhdGEyICU+JSANCiAgZ3JvdXBfYnkocGFydGljbGVfc2l6ZSxTYW1wbGVfSUQsRGlsdXRpb25fZmFjdG9yLEluamVjdGlvbikgJT4lIA0KICBzdW1tYXJpc2UoIHRlY2hfTiA9IGxlbmd0aChUcnVlX0NvdW50KSwNCiAgICAgICAgICAgICB0ZWNoX21lYW4gPSBtZWFuKFRydWVfQ291bnQpLA0KICAgICAgICAgICAgIHRlY2hfc2QgPSBzZChUcnVlX0NvdW50KSwNCiAgICAgICAgICAgICB0ZWNoX3NlID0gdGVjaF9zZC9zcXJ0KHRlY2hfTikpDQpkYXRhMw0KYGBgDQoNCiMjU3VtbWFyaXplIHNhbXBsZXMgYnkgaW5qZWN0aW9uIChhdmVyYWdlIGJvdGggaW5qZWN0aW9ucykNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KDQpkYXRhNCA8LSBkYXRhMyAlPiUgDQogIGdyb3VwX2J5KHBhcnRpY2xlX3NpemUsU2FtcGxlX0lELERpbHV0aW9uX2ZhY3RvcikgJT4lIA0KICBzdW1tYXJpc2UoIGlual9OID0gbGVuZ3RoKHRlY2hfbWVhbiksDQogICAgICAgICAgICAgaW5qX21lYW4gPSBtZWFuKHRlY2hfbWVhbiksDQogICAgICAgICAgICAgaW5qX3NkID0gc2QodGVjaF9tZWFuKSwNCiAgICAgICAgICAgICBpbmpfc2UgPSBpbmpfc2Qvc3FydChpbmpfTikpDQpkYXRhNA0KDQojIEF2ZXJhZ2UgdGVjaG5pY2FsIHJlcGxpY2F0ZXMgYW5kIG1lcmdlIHdpdGgga2V5DQptZXJnZSA8LSBsZWZ0X2pvaW4oa2V5LGRhdGEzLCBieT0gIlNhbXBsZV9JRCIpDQoNCm1lcmdlDQoNCiMgU2F2ZSBhcyAuY3N2DQojIHdyaXRlX2NzdihtZXJnZSwiVGVjaG5pY2FsX3JlcGxpY2F0ZV9hdmVyYWdlLmNzdiIpDQogDQojIEF2ZXJhZ2UgaW5qZWN0aW9uIHJlcGxpY2F0ZXMgYW5kIG1lcmdlIHdpdGgga2V5DQptZXJnZTEgPC0gbGVmdF9qb2luKGtleSxkYXRhNCwgYnk9ICJTYW1wbGVfSUQiKQ0KDQptZXJnZTENCg0KIyAjU2F2ZSBhcyAuY3N2DQojIHdyaXRlX2NzdihtZXJnZTEsIkluamVjdGlvbl9yZXBsaWNhdGVfYXZlcmFnZS5jc3YiKQ0KDQpgYGANCg0KDQoNCiNRdWljayB2aXN1YWxpemF0aW9ucw0KDQojIyMgR3JhcGhpbmcgYWxsIHNhbXBsZXMNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0Kc2FtcGxlX3Bsb3QgPC0gbWVyZ2UgJT4lDQogIGdncGxvdChhZXMoeD1wYXJ0aWNsZV9zaXplLCB5PXRlY2hfbWVhbixjb2xvcj1JbmplY3Rpb24gKSkrICNwbG90DQogIGdlb21fcmliYm9uKGFlcyh5bWluPXRlY2hfbWVhbi10ZWNoX3NlLA0KICAgICAgICAgICAgICAgICAgeW1heD10ZWNoX21lYW4rdGVjaF9zZSksDQogICAgICAgICAgICAgICAgICBhbHBoYT0wLjIsZmlsbCA9IGFscGhhKCdncmV5MTInLCAwLjIpKSArICNlcnJvciBiYXJzDQogIGdlb21fbGluZShzaXplPTIuMCwgYWxwaGEgPSAwLjgpICsgeGxpbSgwLDUwMCkrICNsaW5lIHNpemUsIHgtYXhpcyBzY2FsZQ0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kPWMoMCwwKSkrICNzZXQgYm90dG9tIG9mIGdyYXBoDQogIHhsYWIoIlBhcnRpY2xlIFNpemUiKSArICMgWCBheGlzIGxhYmVsDQogIHlsYWIoIlxuTWVhbiBQYXJ0aWNsZSBDb25jZW50cmF0aW9uL21sXG4iKSArICMgWSBheGlzIGxhYmVsDQogIGdndGl0bGUoIk5hbm9zaWdodCBIaXN0b2dyYW0gb2ZcbmhDVEJTIHRyZWF0ZWQgd2l0aCBCUFMiKSsgI3RpdGxlDQogIGxhYnMoY29sb3I9IkluamVjdGlvbiIpKyAjTGFiZWwgdGFibGUgdGl0bGUNCiAgZmFjZXRfZ3JpZChUaW1lIH4gVHJlYXRtZW50KQ0KICAjIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIwMCkrDQogICMgYW5ub3RhdGUoInRleHQiLCB4PSAzNTAsIHkgPSAxRTgsIGxhYmVsPSAiMjAwbm0iKQ0KDQpzYW1wbGVfcGxvdA0KDQojIGdnc2F2ZSgiTmFub3NpZ2h0X1NhbXBsZV9IaXN0b2dyYW0ucG5nIiwgcGxvdCA9IHNhbXBsZV9wbG90LA0KIyAgICAgICAgaGVpZ2h0ID0gMTAsIHdpZHRoID0gMTQsIGRwaSA9IDIwMCwgdW5pdHM9ICJpbiIpDQpgYGANCiMjI0ludGVyYWN0aXZlIFBsb3QNCmBgYHtyfQ0KZ2dwbG90bHkoc2FtcGxlX3Bsb3QpDQpgYGANCg0KDQoNCiMjIyBQYXJ0aWNsZSBjb25jZW50cmF0aW9uIHZhbHVlcyBmb3IgZWFjaCBvZiB0aGUgc2FtcGxlcw0KYGBge3J9DQptZXJnZTIgPC0gbWVyZ2UxICU+JSANCiAgZ3JvdXBfYnkoVGltZSwgVHJlYXRtZW50LCBWb2x1bWUsUGF0aWVudF9JRCkgJT4lIA0KICBzdW1tYXJpc2UocGFydGljbGVfY29uYz1zdW0oaW5qX21lYW4pKQ0KbWVyZ2UyDQpgYGANCg0KIyMjIENvcnJlY3QgZm9yIHJlc3VzcGVuc2lvbiB2b2x1bWUNCmBgYHtyfQ0KbWVyZ2UzIDwtIG1lcmdlMiAlPiUgDQogIG11dGF0ZShwYXJ0aWNsZV9jb3VudCA9IChWb2x1bWUvMTAwMCkqcGFydGljbGVfY29uYywgIyBDcmVhdGUgbmV3IGNvbHVtbiB3aXRoIG51bWJlciBvZiBwYXJ0aWNsZXMNCiAgICAgICAgIGNvcnJlY3RlZF9wYXJ0aWNsZV9jb25jID0gKHBhcnRpY2xlX2NvbmMvMUU5KSkgIyBDcmVhdGUgbmV3IGNvbHVtbiB3aXRoIGNvcnJlY3QgcGFydGljbGUgY29uY2VudHJhdGlvbg0KbWVyZ2UzDQoNCiMgU2F2ZSBhcyAuY3N2DQojIHdyaXRlX2NzdihtZXJnZTMsIkFkanVzdGVkX3BhcnRpY2xlX2NvbmNlbnRyYXRpb24uY3N2IikNCg0KYGBgDQoNCg0KIyMjQmFycGxvdA0KYGBge3IsIHdhcm5pbmc9VFJVRX0NCm1lcmdlMyRQYXRpZW50X0lEIDwtIGZhY3RvcihtZXJnZTMkUGF0aWVudF9JRCxsZXZlbHMgPSBjKCcxJywnNScsJzcnKSkNCg0KcGxvdDEgPC0gbWVyZ2UzICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBUcmVhdG1lbnQsIHkgPSBjb3JyZWN0ZWRfcGFydGljbGVfY29uYywgZmlsbCA9IFBhdGllbnRfSUQpKSArDQogIGdlb21fYmFyKGFlcyh0ZXh0ID0gcGFzdGUoIlBhcnRpY2xlIENvbmNlbnRyYXRpb246IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JyZWN0ZWRfcGFydGljbGVfY29uYykpLA0KICAgICAgICAgICBzdGF0PSJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikrDQogIHhsYWIoIlxuVHJlYXRtZW50XG4iKSArICMgWCBheGlzIGxhYmVsDQogIHlsYWIoIlxuTWVhbiBWZXNzaWNsZSBDb25jZW50cmF0aW9uXG4oMTBeOSBwYXJ0aWNsZXMvIG1sKVxuIikgKyAjIFkgYXhpcyBsYWJlbA0KICBnZ3RpdGxlKCJFZmZlY3Qgb2YgQlBTIG9uIEV4dHJhY2VsbHVsYXIgVmVzc2ljbGVcblJlbGVhc2Ugb2YgaENUQnNcbiIpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsMTQsMiksDQogICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDAsMTQpLA0KICAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gYygwLDApKSsgIyBzZXQgYm90dG9tIG9mIGdyYXBoDQogIGxhYnMoY29sb3I9IkNvbmRpdGlvbiIpKyAjIExhYmVsIHRhYmxlIHRpdGxlDQogIGZhY2V0X3dyYXAoflRpbWUpDQoNCiAgDQpwbG90MQ0KDQojIGdnc2F2ZSgiQlBTX3RyZWF0ZWRfaENUQnNfNDhfOTZfZmFjZXRfcGxvdC5wbmciLA0KIyAgICAgICBoZWlnaHQgPSA4LCB3aWR0aCA9IDEwLCBkcGkgPSAzMDAsIHVuaXRzPSAiaW4iKQ0KYGBgDQojI0ludGVyYWN0aXZlIFBsb3QNCmBgYHtyfQ0KZ2dwbG90bHkocGxvdDEpDQpgYGANCg0KIyMjQm94cGxvdA0KYGBge3J9DQpwbG90MiA8LSBtZXJnZTMgJT4lDQogIGdyb3VwX2J5KFRpbWUsIFRyZWF0bWVudCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBUcmVhdG1lbnQsIHkgPSBjb3JyZWN0ZWRfcGFydGljbGVfY29uYywgY29sb3IgPSBQYXRpZW50X0lEICkpICsNCiAgZ2VvbV9ib3hwbG90KGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BKSsNCiAgZ2VvbV9wb2ludChhZXModGV4dCA9IHBhc3RlICgiUGF0aWVudF9JRCIsUGF0aWVudF9JRCkpLHBvc2l0aW9uID0gJ2ppdHRlcicsIHNpemUgPSA1KSsNCiAgeGxhYigiXG5UcmVhdG1lbnRcbiIpICsgIyBYIGF4aXMgbGFiZWwNCiAgeWxhYigiXG5NZWFuIFZlc3NpY2xlIENvbmNlbnRyYXRpb25cbigxMF45IHBhcnRpY2xlcy8gbWwpXG4iKSArICMgWSBheGlzIGxhYmVsDQogIGdndGl0bGUoIkVmZmVjdCBvZiBCUFMgb24gRXh0cmFjZWxsdWxhciBWZXNzaWNsZVxuUmVsZWFzZSBvZiBoQ1RCc1xuIikrDQogIGxhYnMoZmlsbD0gIlRpbWUgKGhyKSIpKw0KICBmYWNldF93cmFwKH5UaW1lKQ0KDQpwbG90Mg0KDQogIyBnZ3NhdmUoIkJQU190cmVhdGVkX2hDVEJzXzQ4Xzk2X3Bsb3QucG5nIiwNCiAjICAgICAgIGhlaWdodCA9IDUsIHdpZHRoID0gNywgZHBpID0gNTAwLCB1bml0cz0gImluIikNCmBgYA0KIyMgSW50ZXJhY3RpdmUgUGxvdA0KYGBge3J9DQpnZ3Bsb3RseShwbG90MikNCmBgYA0KDQoNCg0KDQpgYGB7cn0NCm1lcmdlMyAlPiUgDQogIGdyb3VwX2J5KFRpbWUsVHJlYXRtZW50KSAlPiUgDQogIHN1bW1hcmlzZSggICBOID0gbGVuZ3RoKHBhcnRpY2xlX2NvbmMpLA0KICAgICAgICAgICAgbWVhbiA9IG1lYW4ocGFydGljbGVfY29uYyksDQogICAgICAgICAgICAgIHNkID0gc2QocGFydGljbGVfY29uYyksDQogICAgICAgICAgICAgIHNlID0gc2Qvc3FydChOKSkNCmBgYA0KDQoNCg0KDQojIFN0YXRpc3RpY3MNCg0KYGBge3J9DQp0aWR5KHNoYXBpcm8udGVzdChtZXJnZTMkcGFydGljbGVfY29uYykpDQpgYGANCg0KDQpgYGB7cn0NCmZpdCA8LSBhb3YoY29ycmVjdGVkX3BhcnRpY2xlX2NvbmMgfiBUaW1lICogVHJlYXRtZW50LCBkYXRhPW1lcmdlMykNCg0KdGlkeShmaXQpDQpgYGANCg0KYGBge3J9DQp0dWtleV9maXQgPC0gVHVrZXlIU0QoZml0KQ0KDQp0dWtleSA8LSB0aWR5KHR1a2V5X2ZpdCkNCnR1a2V5DQoNCmBgYA0KDQpgYGB7cn0NCnR1a2V5ICU+JSANCiAgZmlsdGVyKGFkai5wLnZhbHVlIDwwLjA1KSAlPiUgDQogIGFycmFuZ2UoYWRqLnAudmFsdWUpDQpgYGANCg0K